import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.*;

public class homework_06 extends Application {

    private static class Edge {
        int yMax;
        float x;
        float slope;

        Edge(int yMax, float x, float slope) {
            this.yMax = yMax;
            this.x = x;
            this.slope = slope;
        }
    }

    @Override
    public void start(Stage primaryStage) {
        Canvas canvas = new Canvas(300, 300);
        GraphicsContext gc = canvas.getGraphicsContext2D();

        // 设置填充颜色
        gc.setFill(Color.BLUE);

        // 执行扫描线填充
        scanlineFill(gc, Arrays.asList(
                new Point(50, 250),  // (2,2) 放大25倍，y坐标反转
                new Point(50, 125),  // (2,7) 放大25倍，y坐标反转
                new Point(125, 175),// (5,5) 放大25倍，y坐标反转
                new Point(275, 100), // (11,8)放大25倍，y坐标反转
                new Point(275, 225), // (11,3)放大25倍，y坐标反转
                new Point(125, 275)  // (5,1) 放大25倍，y坐标反转
        ));

        // 绘制六边形边框
        gc.setStroke(Color.BLACK);
        gc.setLineWidth(1); // 设置边界线宽度
        drawHexagon(gc);

        StackPane root = new StackPane(canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Scanline Fill Algorithm - Hexagon");
        primaryStage.show();
    }

    private void drawHexagon(GraphicsContext gc) {
        // 按照顺序绘制六边形的边
        gc.strokeLine(50, 250, 50, 125);
        gc.strokeLine(50, 125, 125, 175);
        gc.strokeLine(125, 175, 275, 100);
        gc.strokeLine(275, 100, 275, 225);
        gc.strokeLine(275, 225, 125, 275);
        gc.strokeLine(125, 275, 50, 250);
    }

    private void scanlineFill(GraphicsContext gc, List<Point> polygon) {
        Map<Integer, List<Edge>> edgeTable = new HashMap<>();

        // 构建边表
        for (int i = 0; i < polygon.size(); i++) {
            Point p1 = polygon.get(i);
            Point p2 = polygon.get((i + 1) % polygon.size());

            // 跳过水平边
            if (p1.y == p2.y) continue;

            // 确定边的方向
            boolean upward = p1.y > p2.y; // y轴向下为正方向
            int yMin = upward ? p2.y : p1.y;
            int yMax = upward ? p1.y : p2.y;
            float x = upward ? p2.x : p1.x;
            float slope = (p2.x - p1.x) / (float) (p2.y - p1.y);

            edgeTable.computeIfAbsent(yMin, k -> new ArrayList<>())
                    .add(new Edge(yMax, x, slope));
        }

        // 初始化活动边表
        List<Edge> activeEdges = new ArrayList<>();
        int yStart = Collections.min(edgeTable.keySet());
        int yEnd = polygon.stream().mapToInt(p -> p.y).max().orElse(yStart);

        for (int y = yStart; y < yEnd; y++) {
            // 添加新边
            if (edgeTable.containsKey(y)) {
                activeEdges.addAll(edgeTable.get(y));
            }

            // 移除已完成的边
            int finalY = y;
            activeEdges.removeIf(edge -> finalY >= edge.yMax);

            // 按x坐标排序
            activeEdges.sort(Comparator.comparingDouble(e -> e.x));

            // 填充扫描线
            for (int i = 0; i < activeEdges.size(); i += 2) {
                Edge left = activeEdges.get(i);
                Edge right = activeEdges.get(i + 1);
                int xStart = (int) Math.ceil(left.x);
                int xEnd = (int) Math.floor(right.x);
                if (xEnd > xStart) {
                    gc.fillRect(xStart, y, xEnd - xStart, 1);
                }
            }

            // 更新x坐标
            for (Edge edge : activeEdges) {
                edge.x += edge.slope;
            }
        }
    }

    private static class Point {
        int x;
        int y;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}